/*
  author Sylvain Bertrand <sylvain.bertrand@gmail.com>
  Protected by linux GNU GPLv2
  Copyright 2012-2014
*/
#include <linux/pci.h>
#include <linux/cdev.h>
#include <linux/delay.h>

#include <alga/rng_mng.h>
#include <uapi/alga/pixel_fmts.h>
#include <alga/timing.h>
#include <alga/amd/atombios/atb.h>
#include <uapi/alga/amd/dce6/dce6.h>

#include "mc.h"
#include "rlc.h"
#include "ih.h"
#include "fence.h"
#include "ring.h"
#include "dmas.h"
#include "ba.h"
#include "cps.h"
#include "gpu.h"
#include "drv.h"

#include "regs.h"

void hdp_cache_flush(struct pci_dev *dev)
{
	wr32(dev, 0x1, HDP_MEM_COHERENCY_FLUSH_CTL);
}

void hdp_init(struct pci_dev *dev)
{
	struct dev_drv_data *dd;
	u8 i;
	u32 j;
	u32 hdp_misc_ctl;
	u32 hdp_host_path_ctl;

	dd = pci_get_drvdata(dev);

	for (i = 0, j = 0; i < 32; i++, j += 0x18) {
		wr32(dev, 0x00000000, 0x2c14 + j);
		wr32(dev, 0x00000000, 0x2c18 + j);
		wr32(dev, 0x00000000, 0x2c1c + j);
		wr32(dev, 0x00000000, 0x2c20 + j);
		wr32(dev, 0x00000000, 0x2c24 + j);
	}

	wr32(dev, 0, HDP_REG_COHERENCY_FLUSH_CTL);

	wr32(dev, dd->addr_cfg, HDP_ADDR_CFG);

	/*
	 * maps pci bar 0: use the 256 kB block index of the gpu start
	 * address for vram. 1 GB of gpu address space is mapped.
	 */
	wr32(dev, dd->vram.mng.s >> 8, HDP_BASE);
	wr32(dev, (2 << 7) | (1 << 30), HDP_INFO);
	wr32(dev, 0x3fffffff, HDP_SZ);

	hdp_misc_ctl = rr32(dev, HDP_MISC_CTL);
	hdp_misc_ctl |= HMC_HDP_FLUSH_INVALIDATE_CACHE;
	wr32(dev, hdp_misc_ctl, HDP_MISC_CTL);

	hdp_host_path_ctl = rr32(dev, HDP_HOST_PATH_CTL);
	wr32(dev, hdp_host_path_ctl, HDP_HOST_PATH_CTL);

	udelay(50);
}

void hdp_mgcg_dis(struct pci_dev *dev)
{
	u32 cur;
	u32 want;

	cur = rr32(dev, HDP_HOST_PATH_CTL);
	want = cur  | HHPC_CG_DIS;
	if (cur != want)
		wr32(dev, want, HDP_HOST_PATH_CTL);
}

void hdp_mgcg_ena(struct pci_dev *dev)
{
	u32 cur;
	u32 want;

	cur = rr32(dev, HDP_HOST_PATH_CTL);
	want = cur & ~HHPC_CG_DIS;
	if (cur != want)
		wr32(dev, want, HDP_HOST_PATH_CTL);
}

void hdp_ls_dis(struct pci_dev *dev)
{
	u32 cur;
	u32 want;

	cur = rr32(dev, HDP_MEM_PWR_LS);
	want = cur & ~HMPL_HDP_LS_ENA;
	if (cur != want)
		wr32(dev, want, HDP_MEM_PWR_LS);
}

void hdp_ls_ena(struct pci_dev *dev)
{
	u32 cur;
	u32 want;

	cur = rr32(dev, HDP_MEM_PWR_LS);
	want = cur | HMPL_HDP_LS_ENA;
	if (cur != want)
		wr32(dev, want, HDP_MEM_PWR_LS);
}
